/* Copyright (c) 2016-2020 Enfry Ltd. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Enfry. 
 * You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the agreements
 * you entered into with Enfry.
 */
package com.enfry.common.util.sqlldr;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.enfry.common.util.config.Config;
import com.enfry.common.util.config.ConfigType;
import com.enfry.common.util.constants.SqlLdrConstant;
import com.enfry.common.util.encrypt.MD5Util2;
import com.enfry.common.util.vm.VmMsgUtil;

/**
 * <请简单说明此类用途>
 * @Title com.enfry.util.sqlldr.SqlLdrUtil
 * @author longguangxing
 * @date 2017年11月30日
 */
public class SqlLdrUtil {

	private Logger logger = LoggerFactory.getLogger(getClass());

	private volatile static SqlLdrUtil singleton; 
	/**
	 * ctl文件工作的绝对路径
	 */
	protected static String		ctlWorkPath;
	/**
	 * 数据库连接标识
	 */
	protected static String		connectid;
	/**
	 * 数据库用户名
	 */
	protected static String		username;
	/**
	 * 数据库密码
	 */
	protected static String		password;
	/**
	 * sqlldr命令行字符串
	 */
	protected static String		sqlldrCmdLine;
	
	protected static String		LINE_SEPARATOR;
	
	private SqlLdrUtil(){
		ctlWorkPath = Config.getString(ConfigType.CONFIG_SPRING, "ctlWorkPath");
		connectid = Config.getString(ConfigType.CONFIG_SPRING, "connectid");
		username = Config.getString(ConfigType.CONFIG_SPRING, "jdbc.username");
		password = Config.getString(ConfigType.CONFIG_SPRING, "jdbc.password");
		String str = username + "/" + password + "@" + connectid + " ";
		sqlldrCmdLine = "sqlldr " + str;
		LINE_SEPARATOR = System.getProperty("line.separator");
	}
	
	public static SqlLdrUtil getSingleton() {
		if (singleton == null) {
			synchronized (SqlLdrUtil.class) {
				if (singleton == null) {
					singleton = new SqlLdrUtil();
				}
			}
		}
		return singleton;
	}
	
	public File genCtlFile(File file, String tableName,String workId,String vmMsgType, List<Map<String, Object>> sysTableColumNameList) throws Exception {
		Map<String,Object> head = new HashMap<String, Object>();
		head.put("inFile", "."+File.separator+file.getName());
		head.put("badFile", ctlWorkPath+File.separator+SqlLdrConstant.workId_holder+File.separator+tableName+"_"+workId+".txt");
		head.put("tableName", tableName);
		head.put("columNameList", sysTableColumNameList);
		head.put("type", SqlLdrConstant.sqlldr_ctl);
		String content = VmMsgUtil.getSingleton().createVmFileContent(null, vmMsgType, head);

		File ctlFile = new File(ctlWorkPath + File.separator +workId + File.separator+ tableName + SqlLdrConstant.ctl_file_suffix);
		FileUtils.writeStringToFile(ctlFile, MD5Util2.encodeToString(content),"GBK");//MD5Util.convertMD5(content)

		return ctlFile;
	}
	
	public int executeSqlldr(File ctlFile, String tableName, String workId) throws Exception {
		StringBuilder line = new StringBuilder();
		line.append(sqlldrCmdLine).append(" DIRECT=true").append(" control=").append(ctlFile.getAbsolutePath()).append(" log=")
				.append(tableName).append("_log.txt").append(" rows=1000000 readsize=20971520 bindsize=20971520 ").append(" errors=0");
		//.append(" DIRECT=true")

		int exitValue = executeCommand(line.toString(), ctlWorkPath+ File.separator +workId, tableName);

		return exitValue;
	}

	/**
	 * 数据加工导入节点数据处理
	 * @param ctlFile
	 * @param workPath
	 * @param nodeId
	 * @return
	 * @throws Exception
	 */
	public int executeSqlldrOfDp(File ctlFile, String workPath, String nodeId) throws Exception {
		StringBuilder line = new StringBuilder();
		line.append(sqlldrCmdLine).append(" DIRECT=true").append(" control=").append(ctlFile.getAbsolutePath()).append(" log=")
				.append(nodeId).append("_log.txt").append(" rows=1000000 readsize=20971520 bindsize=20971520 ").append(" errors=0");
//		.append(" DIRECT=true")
		int exitValue = executeCommand(line.toString(), workPath, nodeId);

		return exitValue;
	}
	
	
	private int executeCommand(String line, String workPath, String tableName) throws Exception{
		if (logger.isDebugEnabled()) {
			logger.debug("进入executeCommand方法, 参数: line=" + line + ", workPath=" + workPath + ", tableName=" + tableName);
		}
		int exitValue = -1; // 发生异常时的退出码
		try {
			CommandLine cmdLine = CommandLine.parse(line);
			DefaultExecutor executor = new DefaultExecutor();
			ExecuteWatchdog dog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
			executor.setWatchdog(dog);
			executor.setWorkingDirectory(new File(workPath));
			exitValue = executor.execute(cmdLine);
		}
		catch (Exception e) {
			String typeStr = "";
			if (StringUtils.isNotEmpty(tableName)) {
				typeStr = "操作表类型：[" + tableName + "],";
			}
			logger.error("执行命令[" + line + "]发生错误, " + typeStr + " 原因：" + e.getMessage(), e);
			throw e;
		}

		if (logger.isDebugEnabled()) {
			logger.debug("离开executeCommand方法, 返回: exitValue=" + exitValue);
		}
		return exitValue;
	}
}
